/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

package auxiliar;

import interfaces.Leitor;

import java.awt.image.BufferedImage;
import java.awt.image.WritableRaster;
import java.io.File;
import java.util.Arrays;
import java.lang.Math;
import java.util.StringTokenizer;
import javax.swing.JOptionPane;
/**
 *
 * @author wolgrand
 */
public class Filtros {

    public static void mediaRGB(WritableRaster image, int fator) {

	        float[] rgb = new float[3];


	        float auxR, auxB, auxG;             // Variaveis auxiliares
	        int x1, x2, y1, y2;                 // Coordenadas dos pontos que delimitam a vizinhanca de aplicacao do filtro
	        int width = image.getWidth();       // Largura da imagem
	        int height = image.getHeight();     // Altura da imagem
	        fator = (fator - 1)/2;              // Fator que determina os limites da vizinhanca

	        // Matrizes que irao armazenar os valores de cada banda da imagem
	        char[][] R = new char[width][height];
	        char[][] G = new char[width][height];
	        char[][] B = new char[width][height];

	        // Preenchimento das matrizes
	        for(int i = 0 ; i < width; i++) {
	            for(int j = 0 ; j < height; j++) {

	                image.getPixel(i, j, rgb);
	                R[i][j] = (char)rgb[0];
	                G[i][j] = (char)rgb[1];
	                B[i][j] = (char)rgb[2];

	            }
	        }

	        // Varredura da imagem
	        for(int i = 0 ; i < width; i++) {
	            for(int j = 0 ; j < height; j++) {

	                x1 = i - fator;
	                if(x1 < 0) {
	                    x1 = 0;
	                }

	                x2 = i + fator;
	                if(x2 > width - 1) {
	                    x2 = width - 1;
	                }

	                y1 = j - fator;
	                if(y1 < 0) {
	                    y1 = 0;
	                }

	                y2 = j + fator;
	                if(y2 > height - 1) {
	                    y2 = height - 1;
	                }

	                // Numero de pixels que formam a area de aplicacao do filtro neste instante
	                int size = (x2 - x1 + 1) * (y2 - y1 + 1);

	                auxR = 0;
	                auxG = 0;
	                auxB = 0;

	                // Somatorio dos valores R, G e B dos pixels
	                for(int m = x1; m <= x2; m++) {
	                    for(int n = y1; n <= y2; n++) {

	                        auxR += R[m][n];
	                        auxG += G[m][n];
	                        auxB += B[m][n];

	                    }
	                }

	                // Calculo da media
	                rgb[0] = auxR / size;
	                rgb[1] = auxG / size;
	                rgb[2] = auxB / size;

	                image.setPixel(i, j, rgb);

	            }
	        }

                
	    }


    public static void CCA(WritableRaster image, int fator,double c) {

	        float[] rgb = new float[3];
                float[] med = new float[3];

	        float auxR, auxB, auxG;             // Variaveis auxiliares
                 float varR, varB, varG;
	        int x1, x2, y1, y2;                 // Coordenadas dos pontos que delimitam a vizinhanca de aplicacao do filtro
	        int width = image.getWidth();       // Largura da imagem
	        int height = image.getHeight();     // Altura da imagem
	        fator = (fator - 1)/2;              // Fator que determina os limites da vizinhanca

	        // Matrizes que irao armazenar os valores de cada banda da imagem
	        char[][] R = new char[width][height];
	        char[][] G = new char[width][height];
	        char[][] B = new char[width][height];

	        // Preenchimento das matrizes
	        for(int i = 0 ; i < width; i++) {
	            for(int j = 0 ; j < height; j++) {

	                image.getPixel(i, j, rgb);
	                R[i][j] = (char)rgb[0];
	                G[i][j] = (char)rgb[1];
	                B[i][j] = (char)rgb[2];

	            }
	        }

	        // Varredura da imagem
	        for(int i = 0 ; i < width; i++) {
	            for(int j = 0 ; j < height; j++) {

	                x1 = i - fator;
	                if(x1 < 0) {
	                    x1 = 0;
	                }

	                x2 = i + fator;
	                if(x2 > width - 1) {
	                    x2 = width - 1;
	                }

	                y1 = j - fator;
	                if(y1 < 0) {
	                    y1 = 0;
	                }

	                y2 = j + fator;
	                if(y2 > height - 1) {
	                    y2 = height - 1;
	                }

	                // Numero de pixels que formam a area de aplicacao do filtro neste instante
	                int size = (x2 - x1 + 1) * (y2 - y1 + 1);

	                auxR = 0;
	                auxG = 0;
	                auxB = 0;

                        varR = 0;
	                varG = 0;
	                varB = 0;

	                // Somatorio dos valores R, G e B dos pixels
	                for(int m = x1; m <= x2; m++) {
	                    for(int n = y1; n <= y2; n++) {

	                        auxR += R[m][n];
	                        auxG += G[m][n];
	                        auxB += B[m][n];

	                    }
	                }

	                // Calculo da media
	                med[0] = auxR / size;
	                med[1] = auxG / size;
	                med[2] = auxB / size;

                        for(int m = x1; m <= x2; m++) {
	                    for(int n = y1; n <= y2; n++) {

	                        varR += (R[m][n]-rgb[0])*(R[m][n]-rgb[0]);
                                varG += (G[m][n]-rgb[1])*(G[m][n]-rgb[1]);
                                varB += (B[m][n]-rgb[2])*(B[m][n]-rgb[2]);

	                    }
	                }

                  	varR = varR/size;
                        varG = varG/size;
                        varB = varB/size;

                        rgb[0] = (float) (varR==0?R[i][j]:(med[0] + (c/varR)*(R[i][j]-med[0])));
                        rgb[1] = (float) (varG==0?G[i][j]:(med[1] + (c/varG)*(G[i][j]-med[1])));
                        rgb[2] = (float) (varB==0?B[i][j]:(med[2] + (c/varB)*(B[i][j]-med[2])));

                        rgb[0] = (char) (((rgb[0]>255)||(rgb[0]<0))?R[i][j]:rgb[0]);
                        rgb[1] = (char) (((rgb[1]>255)||(rgb[1]<0))?G[i][j]:rgb[1]);
                        rgb[2] = (char) (((rgb[2]>255)||(rgb[2]<0))?B[i][j]:rgb[2]);

                        //Como tava antes!
                        //rgb[1] = (char) (rgb[1]>255?255:(rgb[1]<0?0:rgb[1]));
                       
                        

	                image.setPixel(i, j, rgb);

	            }
	        }

	    }

      public static void Mediana(WritableRaster raster,int fator){

          int n = (fator-1)/2;
          int lim = fator*fator;
          float[] rgb = new float[3];
          int width = raster.getWidth();       // Largura da imagem
	      int height = raster.getHeight();     // Altura da imagem


       // Matrizes que irao armazenar os valores de cada banda da imagem
        char[][] R = new char[width][height];
        char[][] G = new char[width][height];
        char[][] B = new char[width][height];

                // Preenchimento das matrizes
  //      System.out.println("Lim>> "+lim+" fator>> "+fator+" meio>> "+(int)lim/2);
        for(int i = 0 ; i < width; i++) {
            for(int j = 0 ; j < height; j++) {

                raster.getPixel(i, j, rgb);
                R[i][j] = (char)rgb[0];
                G[i][j] = (char)rgb[1];
                B[i][j] = (char)rgb[2];
            }
        }

        char[]   vetorR = new char[lim];
        char[]   vetorG = new char[lim];
        char[]   vetorB = new char[lim];
        int c;
        int meio = lim/2+1;




        for(int i = 0 ; i < width; i++) {
            for(int j = 0 ; j < height; j++) {



                c=0;
                for(int x=i-n;x<=i+n;x++){
                    for(int y = j-n;y<=j+n;y++,c++){
                        //System.out.println("x>> "+x+"y>> "+y+"c>>"+c);
                        if(!((x<0)||(y<0)||(x>=width)||(y>=height))){

                            vetorR[c] =  R[x][y];
                            vetorG[c] =  G[x][y];
                            vetorB[c] =  B[x][y];
                            //System.out.println("R>> "+R[x][y]+"G>> "+G[x][y]+"B>>"+B[x][y]);
                        }
                        else{
                            vetorR[c] =  0;
                            vetorG[c] =  0;
                            vetorB[c] =  0;

                        }
                    //Transforma matriz em vetor para poder ordenar
//                    vetorR[c] = matrizR[a][b];
//                    vetorG[c] = matrizG[a][b];
//                    vetorB[c] = matrizB[a][b];


                    }
                }

                Arrays.sort(vetorR);
                Arrays.sort(vetorG);
                Arrays.sort(vetorB);

                rgb[0] = vetorR[meio];
                rgb[1] = vetorG[meio];
                rgb[2] = vetorB[meio];
//                System.out.println("C>> "+c);
                raster.setPixel(i, j, rgb);


            }
        }

//System.out.println("Meio: "+meio);
      }



      public static void Negativo(WritableRaster raster){

                float[] rgb = new float[3];
	        int width = raster.getWidth();       // Largura da imagem
	        int height = raster.getHeight();     // Altura da imagem


	        // Preenchimento das matrizes
	        for(int i = 0 ; i < width; i++) {
	            for(int j = 0 ; j < height; j++) {

	                raster.getPixel(i, j, rgb);

                        rgb[0] = (char)255 - rgb[0];
                        rgb[1] = (char)255 - rgb[1];
                        rgb[2] = (char)255 - rgb[2];

            //            System.out.println("R: "+rgb[0]+", G: "+rgb[1]+" , B: "+rgb[2]);
                        raster.setPixel(i,j,rgb);

	            }
	        }

      }


     public static void adcBrilhoAditivo(WritableRaster raster, int c ){

                float[] rgb = new float[3];
	        int width = raster.getWidth();       // Largura da imagem
	        int height = raster.getHeight();     // Altura da imagem


	        // Preenchimento das matrizes
	        for(int i = 0 ; i < width; i++) {
	            for(int j = 0 ; j < height; j++) {

	                raster.getPixel(i, j, rgb);

                        rgb[0] = ((c + rgb[0])>255?255:(char)(c + rgb[0]));
                        rgb[1] = ((c + rgb[1])>255?255:(char)(c + rgb[1]));
                        rgb[2] = ((c + rgb[2])>255?255:(char)(c + rgb[2]));

                        
            //            System.out.println("R: "+rgb[0]+", G: "+rgb[1]+" , B: "+rgb[2]);
                        raster.setPixel(i,j,rgb);

	            }
	        }

     }


         public static void retBrilhoAditivo(WritableRaster raster, int c ){

                float[] rgb = new float[3];
	        int width = raster.getWidth();       // Largura da imagem
	        int height = raster.getHeight();     // Altura da imagem


	        // Preenchimento das matrizes
	        for(int i = 0 ; i < width; i++) {
	            for(int j = 0 ; j < height; j++) {

	                raster.getPixel(i, j, rgb);

                        rgb[0] = ((c + rgb[0])< 0 ? 0 :(char)(c + rgb[0]));
                        rgb[1] = ((c + rgb[1])< 0 ? 0:(char)(c + rgb[1]));
                        rgb[2] = ((c + rgb[2])< 0 ? 0:(char)(c + rgb[2]));


            //            System.out.println("R: "+rgb[0]+", G: "+rgb[1]+" , B: "+rgb[2]);
                        raster.setPixel(i,j,rgb);

	            }
	        }

     }

       public static void adcBrilhoMultiplicativo(WritableRaster raster, double c ){

                float[] rgb = new float[3];
	        int width = raster.getWidth();       // Largura da imagem
	        int height = raster.getHeight();     // Altura da imagem


	        // Preenchimento das matrizes
	        for(int i = 0 ; i < width; i++) {
	            for(int j = 0 ; j < height; j++) {

	                raster.getPixel(i, j, rgb);

                        rgb[0] = ((c * rgb[0])>255?255:(char)(c * rgb[0]));
                        rgb[1] = ((c * rgb[1])>255?255:(char)(c * rgb[1]));
                        rgb[2] = ((c * rgb[2])>255?255:(char)(c * rgb[2]));

            //            System.out.println("R: "+rgb[0]+", G: "+rgb[1]+" , B: "+rgb[2]);
                        raster.setPixel(i,j,rgb);

	            }
	        }

      }

       public static void retBrilhoMultiplicativo(WritableRaster raster, double c ){

                float[] rgb = new float[3];
	        int width = raster.getWidth();       // Largura da imagem
	        int height = raster.getHeight();     // Altura da imagem


	        // Preenchimento das matrizes
	        for(int i = 0 ; i < width; i++) {
	            for(int j = 0 ; j < height; j++) {

	                raster.getPixel(i, j, rgb);

                        rgb[0] = ((c * rgb[0])< 0 ? 0 :(char)(c * rgb[0]));
                        rgb[1] = ((c * rgb[1])< 0 ? 0:(char)(c * rgb[1]));
                        rgb[2] = ((c * rgb[2])< 0 ? 0:(char)(c * rgb[2]));

            //            System.out.println("R: "+rgb[0]+", G: "+rgb[1]+" , B: "+rgb[2]);
                        raster.setPixel(i,j,rgb);

	            }
	        }

      }


      public static void BandaR(WritableRaster raster){

                float[] rgb = new float[3];
	        int width = raster.getWidth();       // Largura da imagem
	        int height = raster.getHeight();     // Altura da imagem


	        // Preenchimento das matrizes
	        for(int i = 0 ; i < width; i++) {
	            for(int j = 0 ; j < height; j++) {

	                raster.getPixel(i, j, rgb);

                        rgb[0] = (char)255 - rgb[0];
                        rgb[1] = 0;
                        rgb[2] = 0;

            //            System.out.println("R: "+rgb[0]+", G: "+rgb[1]+" , B: "+rgb[2]);
                        raster.setPixel(i,j,rgb);

	            }
	        }

      }


      public static void BandaG(WritableRaster raster){

                float[] rgb = new float[3];
	        int width = raster.getWidth();       // Largura da imagem
	        int height = raster.getHeight();     // Altura da imagem


	        // Preenchimento das matrizes
	        for(int i = 0 ; i < width; i++) {
	            for(int j = 0 ; j < height; j++) {

	                raster.getPixel(i, j, rgb);

                        rgb[0] = 0;
                        rgb[1] = (char)255 - rgb[1];
                        rgb[2] = 0;

            //            System.out.println("R: "+rgb[0]+", G: "+rgb[1]+" , B: "+rgb[2]);
                        raster.setPixel(i,j,rgb);

	            }
	        }

      }

      public static void BandaB(WritableRaster raster){

                float[] rgb = new float[3];
	        int width = raster.getWidth();       // Largura da imagem
	        int height = raster.getHeight();     // Altura da imagem


	        // Preenchimento das matrizes
	        for(int i = 0 ; i < width; i++) {
	            for(int j = 0 ; j < height; j++) {

	                raster.getPixel(i, j, rgb);

                        rgb[0] = 0;
                        rgb[1] = 0;
                        rgb[2] = (char)255 - rgb[2];

            //            System.out.println("R: "+rgb[0]+", G: "+rgb[1]+" , B: "+rgb[2]);
                        raster.setPixel(i,j,rgb);

	            }
	        }

      }

      public static void CombinarImagem(WritableRaster raster1,WritableRaster raster2){

                float[] rgb1 = new float[3];
                float[] rgb2 = new float[3];

                if((raster1.getWidth()==raster2.getWidth())&&(raster1.getHeight() == raster2.getHeight())){

	        int width = raster1.getWidth();       // Largura da imagem
	        int height = raster1.getHeight();     // Altura da imagem


	        // Preenchimento das matrizes
	        for(int i = 0 ; i < width; i++) {
	            for(int j = 0 ; j < height; j++) {

	                raster1.getPixel(i, j, rgb1);
                        raster2.getPixel(i, j, rgb2);
                        rgb1[0] = (char)(rgb1[0]+rgb2[0])/2;
                        rgb1[1] = (char)(rgb1[1]+rgb2[1])/2;
                        rgb1[2] = (char)(rgb1[2]+rgb2[2])/2;

            //            System.out.println("R: "+rgb[0]+", G: "+rgb[1]+" , B: "+rgb[2]);
                        raster1.setPixel(i,j,rgb1);

	            }
	        }
                }else{
                    System.err.println("As imagens não possuem as mesmas dimensões");
                }
      }

      static float[] rgb2yuv(float[] rgb){

                float[] yuv = new float[3];

                        yuv[0] = 0.299f * rgb[0] + 0.587f * rgb[1] + 0.114f * rgb[2];
                        yuv[1] = 0.492f * (rgb[2] - yuv[0]);
                        yuv[2] = 0.877f * (rgb[0] - yuv[0]);

                return yuv;
      }

     static float[] yuv2rgb(float[] yuv){

                float[] rgb = new float[3];

                        float r = (float) (yuv[0] + 1.140 * yuv[2]);
                        float g = (float) (yuv[0] - 0.394 * yuv[1] - 0.581 * yuv[2]);
                        float b = (float) (yuv[0] + 2.028 * yuv[1]);

                        rgb[0] = (char)((r>255)? 255 :(r<0? 0 : r));
                        rgb[1] = (char)((g>255)? 255 :(g<0? 0 : g));
                        rgb[2] = (char)((b>255)? 255 :(b<0? 0 : b));

                return rgb;
      }


      public static void rgb_yuv_rgb(WritableRaster raster){

                float[] rgb = new float[3];
                float[] yuv = new float[3];
	        int width = raster.getWidth();       // Largura da imagem
	        int height = raster.getHeight();     // Altura da imagem


	        // Preenchimento das matrizes
	        for(int i = 0 ; i < width; i++) {
	            for(int j = 0 ; j < height; j++) {

	                raster.getPixel(i, j, rgb);

                        yuv = rgb2yuv(rgb);
                        rgb = yuv2rgb(yuv);
                        
                        raster.setPixel(i,j,rgb);

	            }
	        }

      }

      public static void aplicaMascara(WritableRaster raster,String arquivo){

          long inicio = System.currentTimeMillis();
          StringTokenizer st1 = new StringTokenizer(Leitor.ler(new File(arquivo)),";\n");
          StringTokenizer st2 = new StringTokenizer(Leitor.ler(new File(arquivo)),"\n");
          int nLinhas = st2.countTokens();
          int nColunas = st1.countTokens()/nLinhas;
          int nC = (nColunas-1)/2;
          int nL = (nLinhas-1)/2;
          float[] rgb = new float[3];
          int width = raster.getWidth();       // Largura da imagem
	  int height = raster.getHeight();     // Altura da imagem
          double mascara[][] = new double[nLinhas][nColunas];
          double mascaraR[][] = new double[nLinhas][nColunas];
          double mascaraF[][] = new double[nLinhas][nColunas];
          double matrizR[][] = new double[nLinhas][nColunas];
          double matrizG[][] = new double[nLinhas][nColunas];
          double matrizB[][] = new double[nLinhas][nColunas];
          double convR,convG,convB;


          if(nColunas%2 != 1){
                JOptionPane.showMessageDialog(null,"O numero de colunas da matriz (mascara) deve ser impar!","",JOptionPane.ERROR_MESSAGE);
                return;
          }
          if(nLinhas%2 != 1){
                JOptionPane.showMessageDialog(null,"O numero de linhas da matriz (mascara) deve ser impar!","",JOptionPane.ERROR_MESSAGE);
                return;
          }

          //Preenche a matriz
          try{
          for(int i=0;i<nLinhas;i++)
             for(int j=0;j<nColunas;j++)
                mascara[i][j]=Double.parseDouble(st1.nextToken());
          }catch(NumberFormatException e){
                JOptionPane.showMessageDialog(null,"Há algum problema no arquivo:"+arquivo+"!\nAlgum numero da matriz é inválido ou a separação entre\nos elementos da matriz está feito de forma errada!","Erro na leitura da mascara!",JOptionPane.ERROR_MESSAGE);
                return;
          }
          //Rebate a mascara na vertival
          for(int i=0;i<nLinhas;i++)
             for(int j=0;j<nColunas;j++)
               mascaraR[i][nColunas-1-j] = mascara[i][j];

          //Rebate a mascara na horizontal
          for(int j=0;j<nColunas;j++)
              for(int i=0;i<nLinhas;i++)
               mascaraF[nLinhas-1-i][j] = mascaraR[i][j];

//          Imprime mascara rebatida.
//          for(int j=0;j<nLinhas;j++){
//              System.out.println("");
//              for(int i=0;i<nColunas;i++){
//                System.out.print(mascaraF[j][i]+" ");}
//          }
       // Matrizes que irao armazenar os valores de cada banda da imagem
        char[][] R = new char[width][height];
        char[][] G = new char[width][height];
        char[][] B = new char[width][height];

        // Preenchimento das matrizes R G B que representam a imagem
        for(int i = 0 ; i < width; i++) {
            for(int j = 0 ; j < height; j++) {

                raster.getPixel(i, j, rgb);
                R[i][j] = (char)rgb[0];
                G[i][j] = (char)rgb[1];
                B[i][j] = (char)rgb[2];
               
            }
        }

        for(int i = 0 ; i < width; i++) {
            for(int j = 0 ; j < height; j++) {

                 for(int x=i-nL,a=0;x<=i+nL;x++,a++){
                    for(int y = j-nC,b=0;y<=j+nC;y++,b++){

                        if(!((x<0)||(y<0)||(x>=width)||(y>=height))){

                            matrizR[a][b] =  R[x][y];
                            matrizG[a][b] =  G[x][y];
                            matrizB[a][b] =  B[x][y];
                            //System.out.println("R>> "+R[x][y]+"G>> "+G[x][y]+"B>>"+B[x][y]);
                        }
                        else{
                            matrizR[a][b] =  0;
                            matrizG[a][b] =  0;
                            matrizB[a][b] =  0;

                        }

                    }
                }

                convR = 0;
                convG = 0;
                convB = 0;
                for(int a = 0 ; a < nLinhas; a++){
                    for(int b = 0 ; b < nColunas; b++){
                     convR+=matrizR[a][b]*mascaraF[a][b];
                     convG+=matrizG[a][b]*mascaraF[a][b];
                     convB+=matrizB[a][b]*mascaraF[a][b];
                    }
                }
                rgb[0] = (float) (convR<0?0:(convR>255?255:convR));
                rgb[1] = (float) (convG<0?0:(convG>255?255:convG));
                rgb[2] = (float) (convB<0?0:(convB>255?255:convB));

                raster.setPixel(i, j, rgb);
            }
        }
        long fim = System.currentTimeMillis();
        System.out.println("Tempo de execução: "+(fim - inicio)+" milissegundos");
      }

      public static void DeformacaoPorRotacao(BufferedImage imagem,int[][] pontos,int ang[]){

                WritableRaster raster = imagem.getRaster();
                int numeroDeCentros = ang.length;
                float[] rgb = new float[3];
                float[] branco = {255,255,255};
	        int width = raster.getWidth();       // Largura da imagem
	        int height = raster.getHeight();     // Altura da imagem
                float R[][] = new float[width][height];
                float G[][] = new float[width][height];
                float B[][] = new float[width][height];
                System.out.println("Largura= "+width+"   Altura= "+height);
                System.out.println("X= "+pontos[0][0]+"   Y= "+pontos[0][1]);
                int il[] = new int[numeroDeCentros],jl[] = new int[numeroDeCentros],ill=0,jll=0;
                final double pi_180 = Math.PI/180;

                

                for(int i = 0 ; i < width; i++) {
	            for(int j = 0 ; j < height; j++){
                        
                       raster.getPixel(i, j, rgb);
                       R[i][j] = rgb[0];
                       G[i][j] = rgb[1];
                       B[i][j] = rgb[2];
                      raster.setPixel(i, j, branco);
	            }
	        }


	        // Preenchimento das matrizes
	        for(int i = 0 ; i < width; i++) {
	            for(int j = 0 ; j < height; j++) {

	                rgb[0] = R[i][j];
                        rgb[1] = G[i][j];
                        rgb[2] = B[i][j];

                       for(int a = 0; a < numeroDeCentros; a++){
                            il[a] = (int) Math.round((i - pontos[a][0])*Math.cos(ang[a]*pi_180) - (j - pontos[a][1])*Math.sin(ang[a]*pi_180))+pontos[a][0];
                            jl[a] = (int) Math.round((i - pontos[a][0])*Math.sin(ang[a]*pi_180) + (j - pontos[a][1])*Math.cos(ang[a]*pi_180))+pontos[a][1];
                            il[a] = ((il[a]<0) || (il[a]>=width)?0:il[a]);
                            jl[a] = ((jl[a]<0) || (jl[a]>=height)?0:jl[a]);
                            jll += jl[a];
                            ill += il[a];
                       }
                       ill = ill/numeroDeCentros;
                       jll = jll/numeroDeCentros;

                       ill = ((ill<0) || (ill>=width)?0:ill);
                       jll = ((jll<0) || (jll>=height)?0:jll);

                        //System.out.println("("+il+", "+jl+")");
                       raster.setPixel(ill, jll, rgb);
                       ill=jll=0;
	            }
	        }

          
      }

      public static void DeformacaoPorRotacaoRM(BufferedImage imagem,int[][] pontos,int ang[]){

                WritableRaster raster = imagem.getRaster();
                int numeroDeCentros = ang.length;
                float[] rgb = new float[3];
                float[] branco = {255,255,255};
	        int width = raster.getWidth();       // Largura da imagem
	        int height = raster.getHeight();     // Altura da imagem
                float R[][] = new float[width][height];
                float G[][] = new float[width][height];
                float B[][] = new float[width][height];
                System.out.println("Largura= "+width+"   Altura= "+height);
                System.out.println("X= "+pontos[0][0]+"   Y= "+pontos[0][1]);
                int il[] = new int[numeroDeCentros],jl[] = new int[numeroDeCentros],ill=0,jll=0;
                final double pi_180 = Math.PI/180;



                for(int i = 0 ; i < width; i++) {
	            for(int j = 0 ; j < height; j++){

                       raster.getPixel(i, j, rgb);
                       R[i][j] = rgb[0];
                       G[i][j] = rgb[1];
                       B[i][j] = rgb[2];
                      raster.setPixel(i, j, branco);
	            }
	        }


	        // Preenchimento das matrizes
	        for(int i = 0 ; i < width; i++) {
	            for(int j = 0 ; j < height; j++) {

	                rgb[0] = R[i][j];
                        rgb[1] = G[i][j];
                        rgb[2] = B[i][j];

                       for(int a = 0; a < numeroDeCentros; a++){
                            il[a] = (int) Math.round((i - pontos[a][0])*Math.cos(ang[a]*pi_180) - (j - pontos[a][1])*Math.sin(ang[a]*pi_180))+pontos[a][0];
                            jl[a] = (int) Math.round((i - pontos[a][0])*Math.sin(ang[a]*pi_180) + (j - pontos[a][1])*Math.cos(ang[a]*pi_180))+pontos[a][1];
                            il[a] = ((il[a]<0) || (il[a]>=width)?0:il[a]);
                            jl[a] = ((jl[a]<0) || (jl[a]>=height)?0:jl[a]);
                            jll += jl[a];
                            ill += il[a];
                       }
                       ill = ill/numeroDeCentros;
                       jll = jll/numeroDeCentros;

                       ill = ((ill<0) || (ill>=width)?0:ill);
                       jll = ((jll<0) || (jll>=height)?0:jll);

                        //System.out.println("("+il+", "+jl+")");
                       raster.setPixel(ill, jll, rgb);
                       ill=jll=0;
	            }
	        }

                Mediana(raster, 3);

      }

      public static void DeformacaoPorRotacaoLinearMR(BufferedImage imagem,int[][] pontos,int ang[],double m){

                WritableRaster raster = imagem.getRaster();
                int numeroDeCentros = ang.length;
                float[] rgb = new float[3];
                float[] branco = {255,255,255};
	        int width = raster.getWidth();       // Largura da imagem
	        int height = raster.getHeight();     // Altura da imagem
                float R[][] = new float[width][height];
                float G[][] = new float[width][height];
                float B[][] = new float[width][height];
                System.out.println("Largura= "+width+"   Altura= "+height);
                System.out.println("X= "+pontos[0][0]+"   Y= "+pontos[0][1]);
                int il[] = new int[numeroDeCentros],jl[] = new int[numeroDeCentros],ill=0,jll=0;
                final double pi_180 = Math.PI/180;
                double angulo;
                double d;


                for(int i = 0 ; i < width; i++) {
	            for(int j = 0 ; j < height; j++){

                       raster.getPixel(i, j, rgb);
                       R[i][j] = rgb[0];
                       G[i][j] = rgb[1];
                       B[i][j] = rgb[2];
                      raster.setPixel(i, j, branco);
	            }
	        }


	        // Preenchimento das matrizes
	        for(int i = 0 ; i < width; i++) {
	            for(int j = 0 ; j < height; j++) {

	                rgb[0] = R[i][j];
                        rgb[1] = G[i][j];
                        rgb[2] = B[i][j];

                       for(int a = 0; a < numeroDeCentros; a++){
                             d = Math.sqrt(Math.pow(i - pontos[0][0], 2)+Math.pow(j-pontos[0][1], 2));
                             angulo = m*d + ang[a];

                            il[a] = (int) Math.round((i - pontos[a][0])*Math.cos(angulo*pi_180) - (j - pontos[a][1])*Math.sin(angulo*pi_180))+pontos[a][0];
                            jl[a] = (int) Math.round((i - pontos[a][0])*Math.sin(angulo*pi_180) + (j - pontos[a][1])*Math.cos(angulo*pi_180))+pontos[a][1];
                            il[a] = ((il[a]<0) || (il[a]>=width)?0:il[a]);
                            jl[a] = ((jl[a]<0) || (jl[a]>=height)?0:jl[a]);
                            jll += jl[a];
                            ill += il[a];
                       }
                       ill = ill/numeroDeCentros;
                       jll = jll/numeroDeCentros;

                       ill = ((ill<0) || (ill>=width)?0:ill);
                       jll = ((jll<0) || (jll>=height)?0:jll);

                        //System.out.println("("+il+", "+jl+")");
                       raster.setPixel(ill, jll, rgb);
                       ill=jll=0;
	            }
	        }
                Mediana(raster, 5);

      }


      public static void DeformacaoPorRotacaoLinear(BufferedImage imagem,int[][] pontos,int ang[],double m){

                WritableRaster raster = imagem.getRaster();
                int numeroDeCentros = ang.length;
                float[] rgb = new float[3];
                float[] branco = {255,255,255};
	        int width = raster.getWidth();       // Largura da imagem
	        int height = raster.getHeight();     // Altura da imagem
                float R[][] = new float[width][height];
                float G[][] = new float[width][height];
                float B[][] = new float[width][height];
                System.out.println("Largura= "+width+"   Altura= "+height);
                System.out.println("X= "+pontos[0][0]+"   Y= "+pontos[0][1]);
                int il[] = new int[numeroDeCentros],jl[] = new int[numeroDeCentros],ill=0,jll=0;
                final double pi_180 = Math.PI/180;
                double angulo;
                double d;


                for(int i = 0 ; i < width; i++) {
	            for(int j = 0 ; j < height; j++){

                       raster.getPixel(i, j, rgb);
                       R[i][j] = rgb[0];
                       G[i][j] = rgb[1];
                       B[i][j] = rgb[2];
                      raster.setPixel(i, j, branco);
	            }
	        }


	        // Preenchimento das matrizes
	        for(int i = 0 ; i < width; i++) {
	            for(int j = 0 ; j < height; j++) {

	                rgb[0] = R[i][j];
                        rgb[1] = G[i][j];
                        rgb[2] = B[i][j];

                       for(int a = 0; a < numeroDeCentros; a++){
                             d = Math.sqrt(Math.pow(i - pontos[0][0], 2)+Math.pow(j-pontos[0][1], 2));
                             angulo = m*d + ang[a];

                            il[a] = (int) Math.round((i - pontos[a][0])*Math.cos(angulo*pi_180) - (j - pontos[a][1])*Math.sin(angulo*pi_180))+pontos[a][0];
                            jl[a] = (int) Math.round((i - pontos[a][0])*Math.sin(angulo*pi_180) + (j - pontos[a][1])*Math.cos(angulo*pi_180))+pontos[a][1];
                            il[a] = ((il[a]<0) || (il[a]>=width)?0:il[a]);
                            jl[a] = ((jl[a]<0) || (jl[a]>=height)?0:jl[a]);
                            jll += jl[a];
                            ill += il[a];
                       }
                       ill = ill/numeroDeCentros;
                       jll = jll/numeroDeCentros;

                       ill = ((ill<0) || (ill>=width)?0:ill);
                       jll = ((jll<0) || (jll>=height)?0:jll);

                        //System.out.println("("+il+", "+jl+")");
                       raster.setPixel(ill, jll, rgb);
                       ill=jll=0;
	            }
	        }


      }



            public static void DeformacaoPorRotacaoBordas(BufferedImage imagem,int[][] pontos,int ang[]){

                WritableRaster raster = imagem.getRaster();
                //int numeroDeCentros = ang.length;
                float[] rgb = new float[3];
                float[] branco = {255,255,255};
	        int width = raster.getWidth();       // Largura da imagem
	        int height = raster.getHeight();     // Altura da imagem
                float R[][] = new float[width][height];
                float G[][] = new float[width][height];
                float B[][] = new float[width][height];
                int centros[][] = new int[pontos.length + 2*width + 2* height -4][2];
                int angulos[] = new int[pontos.length + 2*width + 2* height -4];
                int il[] = new int[angulos.length],jl[] = new int[angulos.length],ill=0,jll=0;
                final double pi_180 = Math.PI/180;
                

                for(int t =0; t < ang.length; t++){
                    centros[t][0] = pontos[t][0];
                    centros[t][1] = pontos[t][1];
                }

                for(int t = 0, b = ang.length; t < width ;t++,b++  ){
                    centros[b][0] = 0;
                    centros[b][1] = t;

                    centros[b][0] = height-1;
                    centros[b][1] = t;
                }

                for(int t = 0, b = ang.length+2*width; t < height ;t++,b++  ){
                    centros[b][0] = t;
                    centros[b][1] = 0;

                    centros[b][0] = t;
                    centros[b][1] = width-1;
                }

                for(int t = 0; t<ang.length;t++){
                    angulos[t] = ang[t];
                }

                for(int t = ang.length; t<angulos.length; t++){
                    angulos[t] = 0;
                }

                for(int i = 0 ; i < width; i++) {
	            for(int j = 0 ; j < height; j++){

                       raster.getPixel(i, j, rgb);
                       R[i][j] = rgb[0];
                       G[i][j] = rgb[1];
                       B[i][j] = rgb[2];
                      raster.setPixel(i, j, branco);
	            }
	        }

                System.out.println("!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!");
	        
	        for(int i = 0 ; i < width; i++) {
	            for(int j = 0 ; j < height; j++) {

	                rgb[0] = R[i][j];
                        rgb[1] = G[i][j];
                        rgb[2] = B[i][j];

                       for(int a = 0; a < angulos.length; a++){
                            il[a] = (int) Math.round((i - centros[a][0])*Math.cos(angulos[a]*pi_180) - (j - centros[a][1])*Math.sin(angulos[a]*pi_180))+centros[a][0];
                            jl[a] = (int) Math.round((i - centros[a][0])*Math.sin(angulos[a]*pi_180) + (j - centros[a][1])*Math.cos(angulos[a]*pi_180))+centros[a][1];
                            il[a] = ((il[a]<0) || (il[a]>=width)?0:il[a]);
                            jl[a] = ((jl[a]<0) || (jl[a]>=height)?0:jl[a]);
                            jll += jl[a];
                            ill += il[a];
                       }
                       ill = ill/angulos.length;
                       jll = jll/angulos.length;

                       ill = ((ill<0) || (ill>=width)?0:ill);
                       jll = ((jll<0) || (jll>=height)?0:jll);

                        //System.out.println("("+il+", "+jl+")");
                       raster.setPixel(ill, jll, rgb);
                       ill=jll=0;
	            }
	        }

      }

            public static void DeformacaoPorRotacaoBordasLinear(BufferedImage imagem,int[][] pontos,int ang[],double m){

                WritableRaster raster = imagem.getRaster();
                //int numeroDeCentros = ang.length;
                float[] rgb = new float[3];
                float[] branco = {255,255,255};
	        int width = raster.getWidth();       // Largura da imagem
	        int height = raster.getHeight();     // Altura da imagem
                float R[][] = new float[width][height];
                float G[][] = new float[width][height];
                float B[][] = new float[width][height];
                int centros[][] = new int[pontos.length + 2*width + 2* height -4][2];
                int angulos[] = new int[pontos.length + 2*width + 2* height -4];
                int il[] = new int[angulos.length],jl[] = new int[angulos.length],ill=0,jll=0;
                final double pi_180 = Math.PI/180;
                double angulo,d;


                for(int t =0; t < ang.length; t++){
                    centros[t][0] = pontos[t][0];
                    centros[t][1] = pontos[t][1];
                }

                for(int t = 0, b = ang.length; t < width ;t++,b++  ){
                    centros[b][0] = 0;
                    centros[b][1] = t;

                    centros[b][0] = height-1;
                    centros[b][1] = t;
                }

                for(int t = 0, b = ang.length+2*width; t < height ;t++,b++  ){
                    centros[b][0] = t;
                    centros[b][1] = 0;

                    centros[b][0] = t;
                    centros[b][1] = width-1;
                }

                for(int t = 0; t<ang.length;t++){
                    angulos[t] = ang[t];
                }

                for(int t = ang.length; t<angulos.length; t++){
                    angulos[t] = 0;
                }

                for(int i = 0 ; i < width; i++) {
	            for(int j = 0 ; j < height; j++){

                       raster.getPixel(i, j, rgb);
                       R[i][j] = rgb[0];
                       G[i][j] = rgb[1];
                       B[i][j] = rgb[2];
                      raster.setPixel(i, j, branco);
	            }
	        }

                System.out.println("!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!");

	        for(int i = 0 ; i < width; i++) {
	            for(int j = 0 ; j < height; j++) {

	                rgb[0] = R[i][j];
                        rgb[1] = G[i][j];
                        rgb[2] = B[i][j];

                       for(int a = 0; a < angulos.length; a++){

                             d = Math.sqrt(Math.pow(i - centros[0][0], 2)+Math.pow(j-centros[0][1], 2));
                             angulo = (a<ang.length?m*d + angulos[a]:angulos[a]);

                            il[a] = (int) Math.round((i - centros[a][0])*Math.cos(angulo*pi_180) - (j - centros[a][1])*Math.sin(angulo*pi_180))+centros[a][0];
                            jl[a] = (int) Math.round((i - centros[a][0])*Math.sin(angulo*pi_180) + (j - centros[a][1])*Math.cos(angulo*pi_180))+centros[a][1];
                            il[a] = ((il[a]<0) || (il[a]>=width)?0:il[a]);
                            jl[a] = ((jl[a]<0) || (jl[a]>=height)?0:jl[a]);
                            jll += jl[a];
                            ill += il[a];
                       }
                       ill = ill/angulos.length;
                       jll = jll/angulos.length;

                       ill = ((ill<0) || (ill>=width)?0:ill);
                       jll = ((jll<0) || (jll>=height)?0:jll);

                        //System.out.println("("+il+", "+jl+")");
                       raster.setPixel(ill, jll, rgb);
                       ill=jll=0;
	            }
	        }
            }


      public static void expansaoHistograma(WritableRaster raster){

          int N[] = new int[256];
          int width = raster.getWidth();       // Largura da imagem
	  int height = raster.getHeight();     // Altura da imagem
          char[][] R = new char[width][height];
          char[][] G = new char[width][height];
          char[][] B = new char[width][height];
          float[] rgb = new float[3];
          int mim = 0;
          int max = 255;
          int S[] = new int[256];

          //zera histograma
          for(int i=0;i<255;i++)
              N[i]=0;

        // Preenchimento das matrizes R G B que representam a imagem e histograma
        for(int i = 0 ; i < width; i++) {
            for(int j = 0 ; j < height; j++) {

                raster.getPixel(i, j, rgb);
                R[i][j] = (char)rgb[0];
                G[i][j] = (char)rgb[1];
                B[i][j] = (char)rgb[2];
                N[(int)R[i][j]]++;
            }
        }

       //Pega mim

          for(int i = 0;i<255;i++){
              if(N[i]!=0){
                  mim = i;
                  break;
              }
          }

          for(int i = 254;i>=0;i--){
              if(N[i]!=0){
                  max = i;
                  break;
              }
          }

          for(int i = 0;i<255;i++){
              S[i] = (int) Math.round(((i-mim)/((max - mim)*1.0))*254.0);
          }

          for(int i = 0 ; i < width; i++) {
            for(int j = 0 ; j < height; j++) {
                R[i][j] = (char)(S[(int)R[i][j]]>255?255:(S[(int)R[i][j]]<0)?0:S[(int)R[i][j]]);
                rgb[0] = R[i][j];
                rgb[1] = G[i][j];
                rgb[2] = B[i][j];
                raster.setPixel(i,j,rgb);
            }
          }


      }

}